{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# CW-Husky Sequenced Triggers\n",
    "\n",
    "Another new Husky feature is *sequenced triggers*. This is a very powerful feature: it allows the capture (or glitch) to be triggered after a sequence of *multiple* trigger events.\n",
    "\n",
    "For example, you could specify a trigger sequence such that Husky triggers when it gets a UART pattern match trigger followed by a SAD trigger.\n",
    "\n",
    "Additionally, you can (optionally) specify that the SAD trigger must follow the UART trigger by no more than $x$ clock cycles and no less than *y* clock cycles.\n",
    "\n",
    "This notebook explains how to set up the trigger sequencer.\n",
    "\n",
    "For a \"real-world\" application of sequenced triggers, have a look at the [sca205](https://github.com/newaetech/chipwhisperer-jupyter/tree/master/courses/sca205) series of notebooks which culminate by showing in \n",
    "[part 3](../../courses/sca205/uecc_part3_trace_sad.ipynb) the advantages of sequencing a jittery trace trigger with a stable SAD trigger to greatly simplify an ECC attack.\n",
    "\n",
    "But first, let's start with the basics:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "SCOPE=\"OPENADC\"\n",
    "PLATFORM = 'CW308_SAM4S'\n",
    "#PLATFORM = 'CW308_STM32F3'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import chipwhisperer as cw"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%run \"../../Setup_Scripts/Setup_Generic.ipynb\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "By default, the trigger sequencer is disabled. If you already know how to set up triggers on Husky and you're not interested in using the sequencer, then you don't need to change anything."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "When you turn on the sequencer, several more properties appear:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.sequencer_enabled = True\n",
    "print(scope.trigger)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we see that Husky supports `scope.trigger.max_sequenced_triggers = 2` sequenced triggers (4 in the case of Husky Plus). This isn't something you can modify; it's a hardware limitation.\n",
    "\n",
    "Next, you'll notice that `scope.trigger.module` and `scope.trigger.triggers` now become \"`SequenceTriggerList()`\" objects.\n",
    "\n",
    "`SequenceTriggerList` is a convenience class that allows us to set or get the individual trigger modules and their triggers (if you've used Husky's multiple glitches, the same approach is used there).\n",
    "\n",
    "The `scope.trigger` object also prints an easier-to-parse version of the trigger parameters under \"sequence trigger \\#0\" and \"sequence trigger \\#1\" (and \\#2, \\#3 in the case of Husky Plus).\n",
    "\n",
    "We see that by default, all are set to the basic trigger module on tio4 (not very interesting).\n",
    "\n",
    "We'll get to the `window_start` and `window_end` properties later.\n",
    "\n",
    "You can change trigger settings by indexing the `scope.trigger.module` and `scope.trigger.triggers` properties.\n",
    "\n",
    "Let's change the second trigger to the UART trigger module, using the tio2 line:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.module[1] = 'UART'\n",
    "scope.trigger.triggers[1] = 'tio2'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Husky has several trigger modules available:\n",
    "- basic\n",
    "- ADC\n",
    "- SAD\n",
    "- UART\n",
    "- edge_counter\n",
    "- trace\n",
    "\n",
    "**Only the \"basic\" trigger module can be used more than once in a trigger sequence.**\n",
    "\n",
    "We previously set the second trigger module to UART; if you try to set the first trigger module to UART also, you'll get an error:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.module[0] = 'UART'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The UART and trace trigger modules share the same hardware, so they also cannot be both active:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.module[0] = 'trace'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# First trigger sequence: GPIO4 + UART\n",
    "\n",
    "Let's return to our legal trigger sequence: basic on tio4 followed by UART on tio1.\n",
    "\n",
    "With the stock `simpleserial-trace` firmware (the same used in the [02 - Husky Triggers.ipynb](02%20-%20Husky%20Triggers.ipynb) notebook), we could have the trigger sequence initiated by the target's `trigger_high()`, and completed when the target sends its response on tio1.\n",
    "\n",
    "Let's first program the correct firmware:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cw.program_target(scope, prog, \"../../../firmware/mcu/simpleserial-trace/simpleserial-trace-{}.hex\".format(PLATFORM))\n",
    "reset_target(scope)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's first do a non-sequenced, tio4-triggered capture:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.sequencer_enabled = False\n",
    "scope.gain.db = 22\n",
    "scope.adc.presamples = 0\n",
    "scope.adc.samples = 50000\n",
    "basictrace = cw.capture_trace(scope, target, plaintext=bytearray(range(16)), key=bytearray(16), always_send_key=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target.simpleserial_last_read"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see that the target responded with `r7ACA...`, so we'll set our UART trigger to trigger on that (see [02 - Husky Triggers.ipynb](02%20-%20Husky%20Triggers.ipynb) for more on UART trigger setup):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.sequencer_enabled = True\n",
    "scope.trigger.num_triggers = 2\n",
    "\n",
    "scope.trigger.module[0] = 'basic'\n",
    "scope.trigger.triggers[0] = 'tio4'\n",
    "\n",
    "scope.trigger.module[1] = 'UART'\n",
    "scope.trigger.triggers[1] = 'tio1'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.UARTTrigger.enabled = True\n",
    "scope.UARTTrigger.baud = 38400\n",
    "scope.UARTTrigger.set_pattern_match(0, 'r7')\n",
    "scope.UARTTrigger.trigger_source = 0\n",
    "scope.UARTTrigger.rules_enabled = [0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's take note of how long the operation took on our previous capture; we'll use this information later:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cycles = scope.adc.trig_count\n",
    "print('The target operation took %d cycles.' % cycles)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Since the capture will now trigger on the target response, let's set `presamples` to the maximum, so that we can still catch part of the target operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.adc.presamples = 32767"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seqtrace = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.resources import INLINE\n",
    "from bokeh.io import output_notebook\n",
    "output_notebook(INLINE)\n",
    "s = figure(width=1800)\n",
    "s.line(list(range(scope.adc.samples)), basictrace.wave, line_color='blue')\n",
    "s.line(list(range(scope.adc.samples)), seqtrace.wave - 0.5, line_color='red')\n",
    "show(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should see that the red (sequence-triggered) trace is a delayed version of the blue (basic-triggered) trace."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `scope.trigger.window_start` and `scope.trigger.window_end` parameters allow specifying when the second trigger is allowed to occur, relative to the first trigger. When these values are 0, there is no limit: the second trigger can come at any time (following the first trigger).\n",
    "\n",
    "If `scope.trigger.window_start` is set to a non-zero value, then a second trigger which comes earlier than `window_start` clock cycles (of the ADC sampling clock) will be ignored. Having a too-early trigger is ok: the trigger sequencer will remain on the lookout for a legal second trigger. \n",
    "\n",
    "Similarly, if `scope.trigger.window_end` is set to a non-zero value, then a second trigger which comes after `window_end` clock cycles (of the ADC sampling clock) will be ignored. At this point the sequence can be considered \"dead\", however a re-occurence of the *first* trigger can still lead to a successful completion of the sequence (until the capture times out).\n",
    "\n",
    "The window parameters can be particularly useful, for example, when the second trigger is a SAD pattern which could fire several times during the target operation, but you're only interested in SAD triggers that are expected to occur in some relatively narrow window following another trigger. This can in turn make it easier to tune the SAD trigger (i.e. if SAD is only allowed to trigger in a narrow window, then one does not need to be as careful when choosing the SAD reference and threshold).\n",
    "\n",
    "When using `window_start`, it's important to understand that this specifies the earliest time that the trigger event can *start*, which for all trigger modules except for the basic trigger, is earlier than the time when the trigger would actually fire (e.g. with the UART trigger module, it's the *start* of the matching UART pattern must come after `window_start` -- not the end of the UART pattern).\n",
    "\n",
    "Finally, a note on indexing: window parameters are relative to the *previous* trigger. So, the first trigger doesn't have any window parameters (there is nothing for it to be relative to). The first set of window parameters are for the second trigger, and they are relative to the first trigger. In general, `scope.trigger.window_start[i]` and `scope.trigger.window_end[i]` are the window parameters for `scope.trigger.module[i+1]`. (Since Husky supports only 2 sequenced triggers, it has only one set of window parameters; however Husky Plus supports 4 sequenced triggers, so it has three sets of window parameters.)\n",
    "\n",
    "Let's illustrate how the window works using our existing example. First let's set up a window which prevents the trigger sequence from completing, by making the window start well after the target operation is done:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.window_start[0] = cycles*2\n",
    "scope.trigger.window_end[0] = 0\n",
    "failtrace = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You should get a \"Timeout happened during capture\" message, because the trigger sequence didn't fire.\n",
    "\n",
    "Now let's set the window to something that can work: we make the window start shortly before the target operation completes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.window_start[0] = int(cycles*0.9)\n",
    "scope.trigger.window_end[0] = 0\n",
    "seqtrace = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This next part is completely optional, but if you have an external logic analyzer, then some of the internal trigger sequence signals can be routed to the USERIO header; this can be very helpful in understanding why a trigger sequence isn't working as intended:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.userio.mode = 'fpga_debug'\n",
    "scope.userio.fpga_mode = 13"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The `scope.userio.fpga_mode` property doesn't give you any useful information, but after it's set, printing the `scope.userio` object will show you which signal is routed to each USERIO pin:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.userio"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- trigger 0/1 are the internal signals for the first and second triggers of the trigger sequence\n",
    "- \"too early\" is a pulse when the next trigger in the trigger sequence arrives prior to its window. For most trigger modules, this cannot actually happen since the active trigger module is only turned on during its window; the exceptions are the \"basic\" module, and the SAD module *if* `scope.trigger.sad_always_active` is set.\n",
    "- \"too late\" pulses if the trigger that's currently being waited for is not received by the end of its window\n",
    "- \"sequence trigger output\" pulses when the trigger sequence is completed\n",
    "- \"trigger 0 window\" is high when the trigger sequencer is waiting for the first trigger; it goes low when the trigger is received\n",
    "- \"trigger 1 window\" is high when the trigger sequencer is waiting for the second trigger; it goes low when the trigger is received, or its expected window expires\n",
    "- \"armed_and_ready\" is high when the trigger sequencer is active and ready to go\n",
    "\n",
    "If you re-run the captures for both the \"bad\" and \"good\" window setups, you should get a good handle on how the USERIO outputs can be helpful.\n",
    "\n",
    "***Important note**: if you connect a logic analyzer to the USERIO pins, ensure it's well grounded and use quality jumper cables. The internal trigger signals are narrow single-cycle pulses, and less-than-ideal connections can actually mess up the FPGA's proper functioning (i.e. this can cause the capture that would have worked without the logic analyzer to fail). You may need to connect several ground lines between your logic analyzer and Husky.\n",
    "If you suspect this is a problem (i.e. you can't get a sequence-triggered capture to work), try unconnecting from the USERIO pins, or setting `scope.userio.mode` back to `'normal'`.*"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Second trigger sequence: UART + SAD\n",
    "\n",
    "Let's now set up a trigger sequence which doesn't use the basic GPIO4 trigger.\n",
    "\n",
    "The first trigger will be the UART message sent to the target on GPIO2, which is `p00010203....`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target.simpleserial_last_sent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.module[1] = 'SAD' # specify this first to prevent error!\n",
    "scope.trigger.module[0] = 'UART'\n",
    "scope.trigger.triggers[0] = 'tio2'\n",
    "scope.UARTTrigger.set_pattern_match(0, 'p0001020')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The second trigger will be a SAD trigger. Let's grab a suitable SAD reference from the AES operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = figure(width=1800)\n",
    "s.line(list(range(scope.adc.samples)), basictrace.wave, line_color='blue')\n",
    "show(s)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# this will work well for the SAM4S target; if you're using a different target, or different firmware, make sure you use something distinctive:\n",
    "scope.SAD.reference = basictrace.wave[5000:]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "s = figure(width=1800)\n",
    "s.line(list(range(scope.SAD.sad_reference_length)), scope.SAD.reference)\n",
    "show(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Some adjustment to the SAD threshold may be required, but this should be in the right ballpark:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.SAD.threshold = scope.SAD.sad_reference_length * 3"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's disable the sequence window for now:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.window_start = 0\n",
    "scope.trigger.window_end = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seqtrace = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Next let's tighten our sequence window. But first, let's make the UART trigger closer to the start of the operation. The UART pattern matcher is limited to 8 bytes, which is why our pattern was set to:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.UARTTrigger.rules[0]['patt']"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Let's instead match on the *end* of the 'p' message, to move the UART trigger as close as possible to the start of the target operation:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "target.simpleserial_last_sent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.UARTTrigger.set_pattern_match(0, 'c0d0e0f\\n')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our SAD reference was taken from sample 5000 onwards. The SAD module triggers at the *end* of the SAD pattern, plus some latency defined by `scope.SAD.latency`.\n",
    "\n",
    "So let's set a narrow window for the SAD trigger around this:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "trigger_expected = 5000 + scope.SAD.sad_reference_length + scope.SAD.latency"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "...but this is relative to the GPIO4 trigger; here, the UART trigger will actually be a fair bit earlier than the GPIO4 trigger, by about 2650 cycles, so let's account for that:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.window_start = trigger_expected + 2650 - 500\n",
    "scope.trigger.window_end = trigger_expected + 2650 + 500"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seqtrace = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you look at the USERIO pins with a logic analyzer, you should be able to confirm that the 2nd trigger is indeed where we expect it:\n",
    "\n",
    "<img src='img/uart_sad_window.png' width=1600>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Our SAD reference occurs several times during the target operation, so if we move the window, the capture should still work:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.window_end = 0\n",
    "scope.trigger.window_start = trigger_expected + 2650 + 10000"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seqtrace_later = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can visualize this either via the USERIO signals, or by comparing the captured waveforms:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from bokeh.plotting import figure, show\n",
    "from bokeh.resources import INLINE\n",
    "from bokeh.io import output_notebook\n",
    "output_notebook(INLINE)\n",
    "s = figure(width=1800)\n",
    "s.line(list(range(scope.adc.samples)), seqtrace.wave - 0.5, line_color='red')\n",
    "s.line(list(range(scope.adc.samples)), seqtrace_later.wave - 1, line_color='purple')\n",
    "show(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "(Remember that we have `scope.adc.presamples = 32767`; you should recognize the SAD reference pattern, and perfect alignment between the two traces, around there.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Husky-Plus Only: 4 Triggers\n",
    "\n",
    "With the \"regular\" Husky, the maximum number of sequenced triggers is 2, but with the \"Plus\", you can go up to 4; let's show that by adding the basic and ADC level triggers to the mix.\n",
    "\n",
    "The sequence will be UART, GPIO4, SAD, ADC.\n",
    "\n",
    "The UART and SAD triggers will be unchanged; we know that GPIO4 goes high in between, so that's easy; and we'll wrap up the sequence with an easy ADC trigger."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "assert scope._is_husky_plus, \"Sorry, only 2 triggers here :-(\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.trigger.num_triggers = 4\n",
    "\n",
    "scope.trigger.module[1] = 'basic'\n",
    "scope.trigger.triggers[1] = 'tio4'\n",
    "scope.trigger.window_start[0] = 2000\n",
    "scope.trigger.window_end[0] = 3000\n",
    "\n",
    "scope.trigger.module[2] = 'SAD'\n",
    "scope.trigger.window_start[1] = trigger_expected-500\n",
    "scope.trigger.window_end[1] = trigger_expected+500\n",
    "\n",
    "scope.trigger.module[3] = 'ADC'\n",
    "scope.trigger.level = min(basictrace.wave)*0.9\n",
    "scope.trigger.window_start[2] = 1000 # arbitrary!\n",
    "scope.trigger.window_end[2] = 0"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you're probing USERIO, let's change the mode to get access to all 4 internal triggers and their windows:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.userio.fpga_mode = 15"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "scope.userio"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "seqtrace_4triggers = cw.capture_trace(scope, target, bytearray(range(16)), bytearray(16))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With a logic analyzer you can visualize the sequence of triggers:\n",
    "\n",
    "<img src='img/plus_4trigger_sequence.png' width=2000>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Next Steps\n",
    "\n",
    "Check out the [sca205](https://github.com/newaetech/chipwhisperer-jupyter/tree/master/courses/sca205) series of notebooks which culminate by showing in \n",
    "[part 3](../../courses/sca205/uecc_part3_trace_sad.ipynb) the advantages of sequencing a jittery trace trigger with a stable SAD trigger to greatly simplify an ECC attack!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
